// terminal.cpp
#include "terminal.h"
#include <iostream>
#include <qtextcodec.h>
#include <QIODevice>
#include <QGuiApplication>
#include <QClipboard>
#include "tabmanager.h"
#include <windows.h>
#include <QThread>
#include <QTimer>

Terminal::Terminal(QWidget *parent, TabManager *tabManager)
    : QPlainTextEdit(parent),
      process(new QProcess(this)),
      currentCommand(""),
      hideButton(new QPushButton("-", this)),
      inputPosition(0),
      hLayout(new QHBoxLayout()),
      vLayout(new QVBoxLayout()),
      tabManager(tabManager)
{
    exePath = QDir::currentPath() + "/mingw64/bin/";
    //std::cout << exePath.toStdString() << std::endl;

    process->setProcessChannelMode(QProcess::MergedChannels); // 合并标准输出和标准错误

    //std::cout << currentPath.toStdString() << std::endl;
    // 设置样式
    QFont font;
    font.setFamily("Microsoft YaHei");  // 微软雅黑
    font.setPointSize(12);
    setFont(font);
    hideButton->setStyleSheet("background: gray; color: white;");

    // 设置布局
    hLayout->addStretch();
    hLayout->addWidget(hideButton);
    vLayout->addLayout(hLayout);
    vLayout->addStretch();

    this->setLayout(vLayout);

    // 链接
    connect(process, &QProcess::readyRead, this, &Terminal::readOutput);
    connect(hideButton, &QPushButton::clicked, this, &Terminal::hideTerminal);

    // 启动cmd
    currentPath = QCoreApplication::applicationDirPath();
    process->setWorkingDirectory(currentPath);
    process->start("cmd.exe");  // On Windows

    // 初始化键入编辑权限，防止用户删除cmd输出的内容
    commandEnteredNumber = 0;
    setReadOnly(false);
    setUndoRedoEnabled(false);
    appendPlainText("Terminal started. Type a command and press Enter.\n");
    inputPosition = textCursor().position();

    output.clear();

}

Terminal::~Terminal() {
    process->close();
    delete process;
    delete hideButton;
    delete hLayout;
    delete vLayout;
}

void Terminal::cdFilePath(QString path) {
    QString command;

    int lastSlashIndex = path.lastIndexOf('/');
    if (lastSlashIndex != -1) {
        path = path.left(lastSlashIndex) + '/';
    } else return;
    currentPath = path;
    command = QString("cd /d \"%1\"\n").arg(path);
    //std::cout << command.toLocal8Bit().toStdString() << std::endl;
    process->write(command.toLocal8Bit());
}

void Terminal::readOutput() {
    // 转utf8以支持中文
    QByteArray outputBytes = process->readAll();
    output = QString::fromLocal8Bit(outputBytes);

    // 忽略用户自己键入的内容
    int newlinePos = output.indexOf("\n");
    while (newlinePos != -1 && commandEnteredNumber > 0) {
        output = output.mid(newlinePos + 1);
        newlinePos = output.indexOf("\n");
        commandEnteredNumber--;
    }

    // 控制光标位置在最后
    appendPlainText(output);
    moveCursor(QTextCursor::End);
    inputPosition = textCursor().position();

    //std::cout << "#~ " << output.toLocal8Bit().toStdString() << std::endl;
    //std::cout << "%~ " << tabManager->filename.toLocal8Bit().toStdString() << std::endl;
    //std::cout << "*~ " << output.indexOf(tabManager->filename) << std::endl;

    // 处理输出数据
    //std::cout << tabManager->filename.toLocal8Bit().toStdString() << std::endl;
    std::vector <int> indexOfFilename;
    indexOfFilename.push_back(output.indexOf(tabManager->filename + ':'));
    while(indexOfFilename.back() != -1) {
        indexOfFilename.push_back(output.indexOf(tabManager->filename + ":", indexOfFilename[indexOfFilename.size() - 1] + 1));
    }
    for(int i = 0; indexOfFilename[i] != -1; ++i) {
        int indexOfError = output.indexOf("error:", indexOfFilename[i]);
        //std::cout << "index of err:" << indexOfError << "txt: " << output.right(0).toLocal8Bit().toStdString() << std::endl;
        if((indexOfFilename[i + 1] == -1 || indexOfError < indexOfFilename[i + 1]) && indexOfError != -1) {
            isCompilePass = false;
            int m1 = output.indexOf(":", indexOfFilename[i] + tabManager->filename.length());
            int m2 = output.indexOf(":", m1 + 1);
            int m3 = output.indexOf(":", m2 + 1);
            QString lineNum_s = output.mid(m1 + 1, m2 - m1 - 1);
            QString colNum_s = output.mid(m2 + 1, m3 - m2 - 1);
            QString info;
            if(indexOfFilename[i + 1] == -1)
                info = output.right(output.length() - indexOfError);
            else
                info = output.mid(indexOfError, indexOfFilename[i + 1] - indexOfError);
            errorInfo.push_back(std::make_pair(std::make_pair(lineNum_s.toInt(), colNum_s.toUInt()), info));
        }
    }
    if(output.lastIndexOf(">") != -1 && output.length() - output.lastIndexOf(">") <= 1) {
        if(loop.isRunning()) {
            loop.quit();
        }
    }
}

void Terminal::hideTerminal() {
    if (isVisible()) hide();
}
void Terminal::showTerminal() {
    if (!isVisible()) show();
}
void Terminal::toggleTerminal() {
    if (!isVisible()) show();
    else hide();
}

bool Terminal::onBuild() {
    if(!tabManager->on_save()) {
        QMessageBox::critical(nullptr, "错误", "文件未保存");
        return false;
    }
    show();
    QString path = tabManager->filename;
    QString target = path;
    if(target.lastIndexOf(".cpp") != -1) {
        // 编译c++程序
        target = target.left(target.lastIndexOf(".cpp"));
        QString command = exePath + "g++ -o " + target + " " + tabManager->compilerOption->compilerOptions + " " + path + "\n";
        process->write(command.toLocal8Bit());
    } else if(target.lastIndexOf(".c") != -1) {
        // 编译c程序
        target = target.left(target.lastIndexOf(".c"));
        QString command = exePath + "gcc -o " + target + " " + tabManager->compilerOption->compilerOptions + " " + path + "\n";
        process->write(command.toLocal8Bit());
    } else {
        target = target.left(target.lastIndexOf("."));
        QString command = exePath + "g++ -o " + target + " " + tabManager->compilerOption->compilerOptions + " " + path + "\n";
        process->write(command.toLocal8Bit());
    }
    isCompilePass = true;
    errorInfo.clear();
    // 延时等待编译器
    loop.exec();
    if(!isCompilePass) {
        tabManager->text1->syntaxHighlighter->setDebugInfo(errorInfo);
        std::cout << "Error:" << std::endl;
        for(int i = 0; i < (int)errorInfo.size(); ++i) {
            std::cout << "Line = " << errorInfo[i].first.first << ", Col = " << errorInfo[i].first.second << ", Info: " << errorInfo[i].second.toLocal8Bit().toStdString() << std::endl;
        }
        /*在这里触发高亮错误行列的槽函数*/
        return false;
    } else {
        std::cout << "Compile Passed!" << std::endl;
        tabManager->text1->syntaxHighlighter->setDebugInfo(errorInfo);
        return true;
    }
}

void Terminal::onRun() {
    QString target = tabManager->filename;
    if(target.lastIndexOf(".cpp") != -1) {
        // 运行c++程序
        target = target.left(target.lastIndexOf(".cpp"));
        QFileInfo fileInfo(target + ".exe");
        if (!fileInfo.exists()) {
            QMessageBox::critical(nullptr, "错误", "文件未编译");
            return;
        }
    } else if(target.lastIndexOf(".c") != -1) {
        // 运行c程序
        target = target.left(target.lastIndexOf(".c"));
        QFileInfo fileInfo(target + ".exe");
        if (!fileInfo.exists()) {
            QMessageBox::critical(nullptr, "错误", "文件未编译");
            return;
        }
    } else {
        target = target.left(target.lastIndexOf("."));
        QFileInfo fileInfo(target + ".exe");
        if (!fileInfo.exists()) {
            QMessageBox::critical(nullptr, "错误", "文件未编译");
            return;
        }
    }
    // 在cmd中运行程序
    QProcess *cmd = new QProcess();
    cmd->setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args)
    {
        args->flags |= CREATE_NEW_CONSOLE;
        args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES;
        args->startupInfo->dwFlags |= STARTF_USEFILLATTRIBUTE;
        args->startupInfo->dwFillAttribute = BACKGROUND_BLUE | FOREGROUND_RED
                                            | FOREGROUND_INTENSITY;
    });
    // 设置要执行的命令行命令
    QString program = "cmd.exe";
    QStringList arguments = { "/c", target + ".exe & echo. & echo -------------------------------- & echo Process exited with return value %errorlevel% & pause" };
    // 启动
    cmd->start(program, arguments);
}

bool Terminal::onBuildAndRun() {
    if(!onBuild()) return false;
    else {
        //std::cout << "WAIT" << std::endl;
        QTimer::singleShot(3000, &loop, SLOT(quit()));  // 阻塞3s
        loop.exec();
        onRun();
    }
    return true;
}

void Terminal::keyPressEvent(QKeyEvent *event) {

    if (textCursor().position() < inputPosition && event->key() != Qt::Key_Backspace) {
        moveCursor(QTextCursor::End);
    }

    if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
        QString command = currentCommand.trimmed();
        if (!command.isEmpty()) {
            process->write(command.toLocal8Bit() + '\n');
            if(process->state() == 0) {
                process->kill();
                process->setWorkingDirectory(currentPath);
                process->start("cmd.exe");  // On Windows
                process->write(command.toLocal8Bit() + '\n');
            }

            currentCommand.clear();
            output.clear();
            commandEnteredNumber++;

            while(!commandQueue2.empty()) {
                commandQueue1.push_back(commandQueue2.front());
                commandQueue2.pop_front();
            }

            commandQueue1.push_back(command);  // 保存历史指令
            if(commandQueue1.size() > 100) commandQueue1.pop_front();

        }
        appendPlainText("");  // 换行
        moveCursor(QTextCursor::End);
        inputPosition = textCursor().position();
        event->accept();
    } else if (event->key() == Qt::Key_Backspace) {
        if (textCursor().position() > inputPosition) {
            QPlainTextEdit::keyPressEvent(event);
            if (!currentCommand.isEmpty()) {
                currentCommand.chop(1);
            }
        }
        event->accept();
    } else {
        if (event->matches(QKeySequence::Paste)) {
            QPlainTextEdit::keyPressEvent(event);
            QClipboard *clipboard = QGuiApplication::clipboard();
            currentCommand += clipboard->text();
        } else {
            if(event->key() == Qt::Key_Up && !commandQueue1.empty()) {
                currentCommand = commandQueue1.back();
                commandQueue2.push_front(currentCommand);
                commandQueue1.pop_back();
                // 删除
                moveCursor(QTextCursor::End);
                QTextCursor cursor = textCursor();
                cursor.setPosition(inputPosition, QTextCursor::KeepAnchor);  // KeepAnchor 保持选中范围
                cursor.removeSelectedText();
                setTextCursor(cursor);
                cursor.insertText(currentCommand);
                return;
            }
            if(event->key() == Qt::Key_Down && !commandQueue2.empty()) {
                currentCommand = commandQueue2.front();
                commandQueue1.push_back(currentCommand);
                commandQueue2.pop_front();
                // 删除
                moveCursor(QTextCursor::End);
                QTextCursor cursor = textCursor();
                cursor.setPosition(inputPosition, QTextCursor::KeepAnchor);  // KeepAnchor 保持选中范围
                cursor.removeSelectedText();
                setTextCursor(cursor);
                cursor.insertText(currentCommand);
                return;
            }
            QPlainTextEdit::keyPressEvent(event);
            currentCommand += event->text();
        }
    }
}

void Terminal::inputMethodEvent(QInputMethodEvent *event) {
    QString commitString = event->commitString();
    if (!commitString.isEmpty()) {
        currentCommand += commitString;
    }
    QPlainTextEdit::inputMethodEvent(event);
}
